package util

import (
	"reflect"
)

// VoToDto 将源结构体 vo 的字段值复制到目标结构体 dto 中
// 仅复制那些在目标结构体中有对应字段的字段值
func convertObjAll(vo any, dto any) any {
	if vo == nil || dto == nil {
		return nil
	}

	// 获取 vo 和 dto 的 reflect.Value 对象
	voVal := reflect.ValueOf(vo).Elem()
	dtoVal := reflect.ValueOf(dto).Elem()

	// 创建一个 map 来存储 dto 字段名称到字段 reflect.Value 的映射
	dtoFieldMap := make(map[string]reflect.Value)

	// 填充 dtoFieldMap
	for i := 0; i < dtoVal.NumField(); i++ {
		field := dtoVal.Type().Field(i)
		dtoFieldMap[field.Name] = dtoVal.Field(i)
	}

	// 遍历 vo 的字段
	for i := 0; i < voVal.NumField(); i++ {
		// 获取 vo 中的字段值
		voField := voVal.Field(i)
		if !voField.IsValid() {
			continue
		}

		// 获取 vo 的字段名称
		fieldName := voVal.Type().Field(i).Name

		// 查找 dto 中是否有对应的字段
		dtoField, exists := dtoFieldMap[fieldName]
		if !exists || !dtoField.CanSet() {
			continue
		}

		// 复制 vo 字段值到 dto 字段
		dtoField.Set(voField)
	}
	return dto
}

// convertObjOmit
// 1. 传入source、target、属性name[]
// 2. 将source的属性传入target对应的属性，但是只挑选出属性name[]的
func convertObjOmit(source any, target any, fields []string) any {
	if source == nil || target == nil {
		return nil
	}

	// 获取 source 和 target 的 reflect.Value 对象
	sourceVal := reflect.ValueOf(source).Elem()
	targetVal := reflect.ValueOf(target).Elem()

	// 创建一个 map 来存储 target 字段名称到字段 reflect.Value 的映射
	targetFieldMap := make(map[string]reflect.Value)

	// 填充 targetFieldMap,只填充fields中的字段
	for i := 0; i < targetVal.NumField(); i++ {
		for j := 0; j < len(fields); j++ {
			if targetVal.Type().Field(i).Name == fields[j] {
				field := targetVal.Type().Field(i)
				targetFieldMap[field.Name] = targetVal.Field(i)
			}
		}
	}

	// 遍历 source 的字段
	for i := 0; i < sourceVal.NumField(); i++ {
		// 获取 source 中的字段值
		sourceField := sourceVal.Field(i)
		if !sourceField.IsValid() {
			continue
		}

		// 获取 source 的字段名称
		fieldName := sourceVal.Type().Field(i).Name

		// 查找 target 中是否有对应的字段
		targetField, exists := targetFieldMap[fieldName]
		if !exists || !targetField.CanSet() {
			continue
		}

		// 复制 source 字段值到 target 字段
		targetField.Set(sourceField)
	}
	return target

}

// convertObjPick
// 传入source、target、属性name[]
// 将source的属性传入target对应的属性，但是排除掉属性name[]的
func convertObjPick(source any, target any, fields []string) any {
	if source == nil || target == nil {
		return nil
	}
	// 获取 source 和 target 的 reflect.Value 对象
	sourceVal := reflect.ValueOf(source).Elem()
	targetVal := reflect.ValueOf(target).Elem()

	// 创建一个 map 来存储 target 字段名称到字段 reflect.Value 的映射
	targetFieldMap := make(map[string]reflect.Value)

	// 填充 targetFieldMap,但是去除掉fields中的字段
	for i := 0; i < targetVal.NumField(); i++ {
		for j := 0; j < len(fields); j++ {
			if targetVal.Type().Field(i).Name != fields[j] {
				field := targetVal.Type().Field(i)
				targetFieldMap[field.Name] = targetVal.Field(i)
			}
		}
	}

	// 遍历 source 的字段
	for i := 0; i < sourceVal.NumField(); i++ {
		// 获取 source 中的字段值
		sourceField := sourceVal.Field(i)
		if !sourceField.IsValid() {
			continue
		}

		// 获取 source 的字段名称
		fieldName := sourceVal.Type().Field(i).Name

		// 查找 target 中是否有对应的字段
		targetField, exists := targetFieldMap[fieldName]
		if !exists || !targetField.CanSet() {
			continue
		}

		// 复制 source 字段值到 target 字段
		targetField.Set(sourceField)
	}
	return target

}
